#!/usr/bin/python
# -*- coding: UTF-8 -*-

import os
import fileutils

cwd = os.getcwd()
execute = os.path.join(cwd, 'pbc_decode.exe')
exec_proto = os.path.join(cwd, 'protoc.exe')
source_dir = os.path.join(cwd, 'source')
target_dir = os.path.join(cwd, 'target')

proto_packages = [ 'cc.qidea.wow.protocol.', 'cc.qidea.wow.client.battle.' ]
proto_java_packages = [ 'option java_package = \"cc.qidea.wow.protocol\";', 'option java_package = \"cc.qidea.wow.client.battle\";' ]
proto_java_classname = 'option java_outer_classname = \"%s\";'

def exec_cmd(source, target, proto_n, pb_n):
    try:
        cmd = '%s %s %s' % (execute, source, target)
        #print (cmd)
        if os.system(cmd) != 0:
            raise Exception('cmd [%s] exec failed .' % cmd)
        else:
            print ('out -> %s' % target)
    except Exception as e:
        raise Exception(e)
    finally:
        #os.chdir(target_dir)
        #exec_cmd_proto(target_dir, proto_n, pb_n)
        pass
    pass

# source pb路径
def exec_cmd_proto(source, proto, pb_n):
    if not os.path.isdir(source):
        os.mkdir(source)            
    cmd = '%s --descriptor_set_out %s %s' % (exec_proto, pb_n, proto)
    print (cmd)
    if os.system(cmd) != 0:
        #raise Exception('cmd [%s] exec failed .' % cmd)
        pass
    else:
        print ('out -> %s' % source)

def exec_cmd_java_proto(source, proto_name):
    cmd = '%s ./%s --java_out=./' % (exec_proto, proto_name)
    print (cmd)
    if os.system(cmd) != 0:
        #raise Exception('cmd [%s] exec failed .' % cmd)
        pass
    else:
        print ('out -> %s' % proto_name)
    pass

def walk_source():
    if not os.path.isdir(source_dir):
        raise Exception('source_dir [%s] is not exist .' % source_dir)
    fileutils.cleartree(target_dir)
    def __walk__(file):
        adbpath = file.replace(source_dir, '')
        source = file
        target = target_dir + adbpath
        parent = os.path.dirname(target)
        name = os.path.basename(target).capitalize()
        proto_n = os.path.splitext(name)[0] + 'Proto.proto'
        pb_n = os.path.basename(target)
        target = os.path.join(parent, proto_n)   
        if not os.path.isdir(parent):
            os.makedirs(parent)
        #print (target)
        exec_cmd(source, target, './' + proto_n, './' + pb_n)
        pass
    fileutils.walkfile(source_dir, __walk__, ['.pb'])
    pass

def find_import(message_name, enum_name):
    files = []
    has = False
    file_name = None
    def __walk__(file):
        files.append(file)
    fileutils.walkfile(target_dir, __walk__, ['.proto'])
    for file in files:
        file_name = os.path.basename(file)
        with open(file) as f:
            content = f.read()
            if message_name in content:
                #print (file_name)
                has = True
                break
            if enum_name in content:
                #print (file_name)
                has = True
                break
        pass
    if has:
        return file_name
    pass

def check_import(c, content, imports):
    for proto_package in proto_packages:
        if proto_package in c:
            #print (content)
            fields = c.split(' ')
            #print (c)
            field_type = fields[3]
            field_type_name = field_type.replace(proto_package, '')
            names = field_type_name.split('.')
            if len(names) > 1:
                field_type_name = names[0]
                pass
            message_name = 'message %s' % field_type_name
            enum_name = 'enum %s' % field_type_name
            if message_name in content:
                break
            if enum_name in content:
                break
            #print (c)
            import_name = find_import(message_name, enum_name)
            if import_name:
                if import_name in imports:
                    break

                #print (import_name)
                imports.append(import_name)
                break
            break
        pass

def read_proto(file):
    file_name = os.path.basename(file)
    content = ''
    import_string = ''
    imports = []
    contents = []
    new_contents = []
    with open(file, 'r') as f:
        content = f.read()        
    with open(file, 'r') as f:
        contents = f.readlines()
        for c in contents:
            check_import(c, content, imports)
        pass
    if len(imports) > 0:
        for imp in imports:
            string = 'import %s;\n' % imp
            import_string = import_string + string
    for c in contents:
        new_contents.append(c)
        # check header
        index = 0
        for proto_java_package in proto_java_packages:
            if proto_java_package in c:
                java_class = proto_java_classname % os.path.splitext(file_name)[0]
                if proto_java_classname not in content:
                    new_contents.append('\n')
                    new_contents.append(java_class)
                    new_contents.append('\n')
                if import_string != '' and import_string not in content:
                    new_contents.append('\n')
                    new_contents.append(import_string)
                    new_contents.append('\n')
                break
            index = index + 1
    with open(file, 'w') as f:
        f.writelines(new_contents)
    print ('%s is write import .' % file)
    pass

def export_lua_pb():
    os.chdir(target_dir)
    def __walk__(file):
        adbpath = file.replace(target_dir, '')
        source = file
        target = target_dir + adbpath
        parent = os.path.dirname(target)
        name = os.path.basename(target)
        proto_n = name
        pb_n = name.replace('Proto.proto', '').lower() + '.pb'
        target = os.path.join(parent, proto_n)   
        if not os.path.isdir(parent):
            os.makedirs(parent)
        #print ('%s => %s' % proto_n, pb_n)
        exec_cmd(source, target, './' + proto_n, './' + pb_n)
        pass
    fileutils.walkfile(target_dir, __walk__, ['.proto'])

def walk_proto():
    files = []
    def __walk__(file):
        read_proto(file)
        files.append(file)
        pass
    fileutils.walkfile(target_dir, __walk__, ['.proto'])

    os.chdir(target_dir)

    for file in files:
        file_name = os.path.basename(file)
        exec_cmd_java_proto(target_dir, file_name)
    pass

def main():
    try:
        walk_source()
        walk_proto()
        #export_lua_pb()
    except Exception as e:
        print (e)
    finally:
        print ('decode success ! to -> %s' % target_dir)
    pass

if __name__ == '__main__':
    main()
    pass